package com.situ.mall.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.situ.mall.exception.SituException;
import com.situ.mall.mapper.ProductMapper;
import com.situ.mall.pojo.Product;
import com.situ.mall.pojo.query.ProductQuery;
import com.situ.mall.service.IProductService;
import com.situ.mall.util.PageResult;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class ProductServiceImpl implements IProductService {
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public PageResult<Product> list(ProductQuery productQuery) {
        PageHelper.startPage(productQuery.getPage(), productQuery.getLimit());
        List<Product> list = productMapper.list(productQuery);
        PageInfo pageInfo = new PageInfo(list);
        int count = (int) pageInfo.getTotal();
        //if (count > 0) {
        //    throw new SituException("自定义异常");
        //}
        return new PageResult<>(0, "", count, list);
    }

    @Override
    public Product selectById(Integer id) {
        //1.先去缓存中拿
        Product product = (Product) redisTemplate.opsForValue().get("product:" + id);
        //2.缓存中没有
        if (product == null) {
            //只有当缓存中没有时候，才需要加锁
            //1、2、3、4 多个线程都想访问缓存中的共享数据
            redissonClient.getLock("product_lock_" + id).lock();
            try {
                //双重检查机制
                product = (Product) redisTemplate.opsForValue().get("product:" + id);
                if (product == null) {
                    //3.查询数据库
                    product = productMapper.selectByPrimaryKey(id);
                    if (product != null) {
                        //4.更新到缓存中
                        redisTemplate.opsForValue().set("product:" + id, product, 1, TimeUnit.DAYS);
                    } else {
                        //4.更新到缓存中,缓存空对象
                        redisTemplate.opsForValue().set("product:" + id, new Product(), 1, TimeUnit.MINUTES);
                    }
                }
            } finally {
                redissonClient.getLock("product_lock_" + id).unlock();
            }
        }
        return product;
    }

    //160
    //@Override
    public Product selectById2(Integer id) {
        //1.先去缓存中拿
        Product product = (Product) redisTemplate.opsForValue().get("product:" + id);
        //2.缓存中没有
        if (product == null) {
            //只有当缓存中没有时候，才需要加锁
            //1、2、3、4 多个线程都想访问缓存中的共享数据
             synchronized (this) {
                 //双重检查机制
                 product = (Product) redisTemplate.opsForValue().get("product:" + id);
                 if (product == null) {
                     //3.查询数据库
                     product = productMapper.selectByPrimaryKey(id);
                     if (product != null) {
                         //4.更新到缓存中
                         redisTemplate.opsForValue().set("product:" + id, product, 1, TimeUnit.DAYS);
                     } else {
                         //4.更新到缓存中,缓存空对象
                         redisTemplate.opsForValue().set("product:" + id, new Product(), 1, TimeUnit.MINUTES);
                     }
                 }

             }

        }
        return product;
    }

    //@Override
    public synchronized Product selectById1(Integer id) {
        //1.先去缓存中拿
        Product product = (Product) redisTemplate.opsForValue().get("product:" + id);
        //2.缓存中没有
        if (product == null) {
            //3.查询数据库
            product = productMapper.selectByPrimaryKey(id);
            if (product != null) {
                //4.更新到缓存中
                redisTemplate.opsForValue().set("product:" + id, product, 1, TimeUnit.DAYS);
            } else {
                //4.更新到缓存中,缓存空对象
                redisTemplate.opsForValue().set("product:" + id, new Product(), 1, TimeUnit.MINUTES);
            }
        }
        return product;
    }

}
